//
// Created by xu on 2024/11/26.
//
#include <stdio.h>
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
#include <libavcodec/avcodec.h>

#define FMT_NAME "dshow"
#define DEVICE_NAME "video=Integrated Camera"
#define FILENAME "D:/out.yuv"

#define ERROR_BUF(ret) \
    char errbuf[1024]; \
    av_strerror(ret, errbuf, sizeof(errbuf));


void logInfo(const char *format, const char *data) {
    av_log(NULL, AV_LOG_INFO, format, data);
}

int main(int argc, char *argv[]) {
    // 注册所有的输入输出设备
    avdevice_register_all();
    // 获取输入格式对象
    const AVInputFormat *fmt = av_find_input_format(FMT_NAME);
    if (!fmt) {
        logInfo("av_find_input_format error %s", FMT_NAME);
        return -1;
    }
    // 格式上下文
    AVFormatContext *ctx = NULL;
    // 传递给输入设备的参数
    AVDictionary *options = NULL;
    av_dict_set(&options, "video_size", "640x480", 0);
    av_dict_set(&options, "pixel_format", "yuyv422", 0);
    av_dict_set(&options, "framerate", "30", 0);

    // 打开输入设备
    int ret = avformat_open_input(&ctx, DEVICE_NAME, fmt, &options);
    if (ret < 0) {
        ERROR_BUF(ret);
        logInfo("avformat_open_input error %s", errbuf);
        return -1;
    }

    // 打开输出文件
    FILE *file = NULL;
    if ((file = fopen(FILENAME, "wb")) < 0) {
        logInfo("file open error %s", FILENAME);
        // 关闭输入设备
        avformat_close_input(&ctx);
        return -1;
    }

    // 计算每一帧的大小
    AVCodecParameters *params = ctx->streams[0]->codecpar;
    int imageSize = av_image_get_buffer_size(params->format, params->width, params->height, 1);
    // 数据包
    AVPacket *pkt = av_packet_alloc();
    int cnt = 50;
    while (cnt > 0) {
        // 不断采集数据
        ret = av_read_frame(ctx, pkt);
        if (ret == 0) {
            // 将数据写入文件
            // 这里要使用imageSize，而不是pkt->size，pkt->size有可能比imageSize大，使用pkt->size会导致写入
            // 一些多余数据到YUV文件中，进而导致YUV内容无法正常播放
            fwrite(pkt->data, 1, imageSize, file);
            // 释放资源
            av_packet_unref(pkt);
            cnt--;
        } else if (ret == AVERROR(EAGAIN)) { // 资源临时不可用
            continue;
        } else {
            ERROR_BUF(ret);
            logInfo("av_read_frame error %s", errbuf);
            break;
        }
    }
    // 释放资源
    av_packet_free(&pkt);
    // 关闭文件
    fclose(file);
    // 关闭设备
    avformat_close_input(&ctx);
    return 0;
}